
/* Generated by Interface Builder */

#import "DrawView.h"

#define PRINTER_PIXEL_FACTOR 67.0		// dpi of screen when printed
#define LINE_WIDTH_FACTOR 1.08			// fudge factor to avoid aliasing

@implementation DrawView

+ newFrame: (NXRect *)rect  
{
	self = [super newFrame:rect]; 
	[self initialValues];
	return self; 
}

- (PROC) initialValues
{
	xmax = 2.0;
	xmin = -2.0;
	ymax = 2.0;
	ymin = -2.0;
	xc = 0.0;
	yc = 1.0;
	iterates = 12;
	large = 10.0;
	running = NO;
	pixelSize = 6;
	colors = 7;
}

- (BOOL) continue	// Ignores all mousedown events until Stop is pressed
{
	NXEvent	*peekedEvent;
	
	peekedEvent = [NXApp peekAndGetNextEvent:NX_MOUSEDOWNMASK];
	if (peekedEvent IS NULL)
		return YES;
	else if (NXPointInRect(&(peekedEvent->location), &stopRect))
	{
		[stopButton highlight:YES];
		running = NO;
		[stopButton highlight:NO];
		return NO;
	}
	else
		return YES;
}

- drawSelf: (NXRect *)rect : (int) count 
{
	NXRect  frameRect;
	int p, q, 				// pixel coords
		pmax, qmax, 		// pixels in screen
		pstart;				// start of line to draw
	float x, y,				// actual coords
		dx, dy,				// distance between pixels
		oldCol, newCol,		// colours of adjacent pixels
		printerDot,			// distance between printer dots 
		lineWidth,			// width 1 on printer is PRINTER_PIXEL_FACTOR
		qHeight;			// vertical position of line to be drawn

	NXEraseRect(&bounds);
	if ((NXDrawingStatus IS NX_DRAWING) AND running)
	{
		[self getParams];
		[self getFrame:&frameRect];
		pmax = (int) frameRect.size.width;
		qmax = (int) frameRect.size.height;
		dx = (xmax - xmin)/pmax;
		dy = (ymax - ymin)/qmax;
		PSsetlinewidth(1.0);
 		for (q = 0, y = ymin; (q <= qmax) AND [self continue]; q++, y += dy)
		{
			for (p = 0, pstart = 0, x = xmin, oldCol = NX_WHITE;
													p <= pmax; p++, x += dx)
			{
				newCol = [self pixelCol:x :y];
				if (newCol IS_NOT oldCol)
				{
					if (oldCol IS_NOT NX_WHITE)
						[self drawline:oldCol :pstart :(p-1) :q];
					pstart = p;
					oldCol = newCol;
				}
			}
			if (oldCol IS_NOT NX_WHITE)
				[self drawline:oldCol :pstart :p :q];
			[window flushWindow];
		}
	}
	else if (NXDrawingStatus IS NX_PRINTING)
	{
		[self getParams];
		[self getFrame:&frameRect];
		printerDot = PRINTER_PIXEL_FACTOR/ 
					atoi(NXGetDefaultValue("System", "PrinterResolution"));
		lineWidth = printerDot*pixelSize;
		pmax = (int) ((frameRect.size.width)/lineWidth);
		qmax = (int) ((frameRect.size.height)/lineWidth);
		dx = (xmax - xmin)/pmax;
		dy = (ymax - ymin)/qmax;
		if (pixelSize > 1)
			PSsetlinewidth(lineWidth*LINE_WIDTH_FACTOR);
		else
			PSsetlinewidth(0);
	 	for (q = 0, y = ymin; (q <= qmax); q++, y += dy)
		{
			qHeight = (q + 0.5)*lineWidth;
			for (p = 0, pstart = 0, x = xmin, oldCol = NX_WHITE; p <= pmax;
					p++, x += dx)
			{
				newCol = [self pixelCol:x :y];
				if (newCol IS_NOT oldCol)
				{
					if (oldCol IS_NOT NX_WHITE)
						[self drawline :oldCol :(pstart*lineWidth) 
										:(p*lineWidth - printerDot) :qHeight];
					pstart = p;
					oldCol = newCol;
				}
			}
			if (oldCol IS_NOT NX_WHITE)
				[self drawline:oldCol :(pstart*lineWidth) :(p*lineWidth) :qHeight];
			[window flushWindow];
		}
	}		
	return self;
}

- (PROC) drawline:(float) col :(float) p1 :(float) p2 :(float) q
{
	PSnewpath();
	PSmoveto(p1, q);
	PSlineto(p2, q);
	PSsetgray(col);
	PSstroke();
}

- (float) pixelCol:(float) x :(float) y
{
	int power;
	float xx, yy;

	xx = x*x;
	yy = y*y;
	power = 0;
	while (((xx + yy) < large) AND (power < iterates))
	{
		++power;
		y = 2*x*y + yc;
		x = xx - yy + xc;		// f(z) = z*z + c
		xx = x*x;
		yy = y*y;
	}
	if (power >= iterates)
		return NX_BLACK;
	else
		return (1.0 + (power MOD (colors - 1)))/(colors - 1);
}

- setParamsForm:anObject
{
    paramsForm = anObject;
	[paramsForm setFloatValue:xc at:0];
	[paramsForm setFloatValue:yc at:1];
	[paramsForm setFloatValue:xmin at:2];
	[paramsForm setFloatValue:ymin at:3];
	[paramsForm setFloatValue:xmax at:4];
	[paramsForm setFloatValue:ymax at:5];
	[paramsForm setIntValue:iterates at:6];
	[paramsForm setFloatValue:large at:7];
	[paramsForm setIntValue:colors at:8];
    return self;
}

- setPopUpButton:anObject
{
  id aPopUp;

  popUpButton = anObject;
  aPopUp = [PopUpList new];
  [aPopUp addItem:"1 dot"];
  [aPopUp addItem:"2x2 dots"];
  [aPopUp addItem:"3x3 dots"];
  [aPopUp addItem:"4x4 dots"];
  [aPopUp addItem:"5x5 dots"];
  [aPopUp addItem:"6x6 dots"];
  [[aPopUp itemList] selectCellAt:pixelSize - 1:0];
  NXAttachPopUpList(popUpButton, aPopUp);
  [aPopUp setTarget:self];
  [aPopUp setAction:@selector(pixelSize:)];
  return self;
}

- setStopButton:anObject
{
	stopButton = anObject;
	[stopButton getFrame:&stopRect];
	return self;
}

- getParams
{
	xc = [paramsForm floatValueAt:0];
	yc = [paramsForm floatValueAt:1];
	xmin = [paramsForm floatValueAt:2];
	ymin = [paramsForm floatValueAt:3];
	xmax = [paramsForm floatValueAt:4];
	ymax = [paramsForm floatValueAt:5];
	iterates = [paramsForm intValueAt:6];
	large = [paramsForm floatValueAt:7];
   	colors = [paramsForm intValueAt:8];
	if (colors < 2) 
		colors = 2;
    return self;
}

- start:sender
{
	running = YES;
	[self display];
    return self;
}

- pixelSize:sender
{
	pixelSize = 1 + [sender selectedRow];
    return self;
}

@end
